package org.xbdframework.boot.autoconfigure.dao;

import javax.sql.DataSource;

import org.xbdframework.dao.BaseDao;
import org.xbdframework.dao.PageHelper;
import org.xbdframework.dao.core.support.XbdJdbcDaoBeanPostProcessor;
import org.xbdframework.dao.support.JdbcDaoImpl;
import org.xbdframework.dao.support.pagehelper.MysqlPageHelper;
import org.xbdframework.dao.support.pagehelper.OraclePageHelper;
import org.xbdframework.jdbc.core.support.JdbcDaoBeanPostProcessor;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

/**
 * {@link BaseDao}、{@link JdbcDaoImpl}自动化配置
 *
 * @author luas
 * @since 1.5.0
 */
@Configuration
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(XbdDaoProperties.class)
@AutoConfigureAfter({ JdbcTemplateAutoConfiguration.class })
public class DaoAutoConfiguration {

	/**
	 * 当前尚未有已实例化的{@link PageHelper}，且存在使用{@link PageHelperCustomizer}自定义{@link PageHelper}时，
	 * 暴露其自定义的{@link PageHelper}.
	 */
	@Configuration
	@ConditionalOnMissingBean(PageHelper.class)
	@ConditionalOnBean(PageHelperCustomizer.class)
	static class CustomizedPageHelperConfiguration {

		private PageHelperCustomizer pageHelperCustomizer;

		public CustomizedPageHelperConfiguration(ObjectProvider<PageHelperCustomizer> pageHelperCustomizerObjectProvider) {
			this.pageHelperCustomizer = pageHelperCustomizerObjectProvider.getIfUnique();
		}

		@Bean
		@ConditionalOnMissingBean(PageHelper.class)
		public PageHelper pageHelper() {
			return this.pageHelperCustomizer.customize();
		}
	}

	/**
	 * 使用{@link PageHelperCustomizer}自定义{@link PageHelper}，且当前尚未有已实例化的{@link PageHelper}，
	 * 尝试使用配置方案初始化{@link PageHelper}.
	 */
	@Configuration
	@ConditionalOnMissingBean({ PageHelper.class, PageHelperCustomizer.class })
	static class AutoConfiguredPageHelperConfiguration {

		@Bean
		@ConditionalOnProperty(prefix = "xbd.dao", name = "dbType", havingValue = "MYSQL")
		public PageHelper mysqlPageHelper() {
			return new MysqlPageHelper();
		}

		@Bean
		@ConditionalOnProperty(prefix = "xbd.dao", name = "dbType", havingValue = "ORACLE", matchIfMissing = true)
		public PageHelper oraclePageHelper() {
			return new OraclePageHelper();
		}
	}

	/**
	 * 初始化默认的{@link BaseDao}实现.
	 */
	@Configuration
	@ConditionalOnClass({ BaseDao.class, PageHelper.class })
	public static class JdbcDaoConfiguration {

		private final JdbcTemplate jdbcTemplate;

		private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;

		private XbdDaoProperties properties;

		private PageHelper pageHelper;

		JdbcDaoConfiguration(JdbcTemplate jdbcTemplate,
				NamedParameterJdbcTemplate namedParameterJdbcTemplate,
				XbdDaoProperties properties, PageHelper pageHelper) {
			this.jdbcTemplate = jdbcTemplate;
			this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
			this.properties = properties;
			this.pageHelper = pageHelper;
		}

		@Bean
		@ConditionalOnMissingBean(BaseDao.class)
		public BaseDao jdbcDaoImpl() {
			return new JdbcDaoImpl();
		}

		@Bean
		@ConditionalOnMissingBean(JdbcDaoBeanPostProcessor.class)
		public BeanPostProcessor xbdJdbcDaoBeanPostProcessor() {
			XbdJdbcDaoBeanPostProcessor xbdJdbcDaoBeanPostProcessor = new XbdJdbcDaoBeanPostProcessor();
			xbdJdbcDaoBeanPostProcessor.setJdbcTemplate(this.jdbcTemplate);
			xbdJdbcDaoBeanPostProcessor.setNamedParameterJdbcTemplate(namedParameterJdbcTemplate);
			xbdJdbcDaoBeanPostProcessor.setPageHelper(this.pageHelper);
			xbdJdbcDaoBeanPostProcessor.setShowSql(this.properties.isShowSql());
			return xbdJdbcDaoBeanPostProcessor;
		}
	}

}
